// #define ENABLE_TEST

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <time.h>
#ifndef ENABLE_TEST
#include "timer_task.h"
#endif

#define BUF_SIZE 512

typedef struct coord
{
    double lat;
    double lng;
    char timezone[32];
} coord_t;

typedef struct sunrise_sunset
{
    time_t sunrise;
    time_t sunset;
} sunrise_sunset_t;

// ===================== 工具函数 =====================
typedef uint8_t (*http_get_cb_t)(char *buf, size_t buf_size, void *user_data);
uint8_t http_get(const char *host, const char *port, const char *path, http_get_cb_t cb, void *user_data)
{
    int sockfd;
    struct addrinfo hints, *res;
    char buf[BUF_SIZE];
    int bytes;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    if (getaddrinfo(host, port, &hints, &res) != 0)
    {
        perror("getaddrinfo");
        return 0;
    }

    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sockfd < 0)
    {
        perror("socket");
        freeaddrinfo(res);
        return 0;
    }

    if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0)
    {
        perror("connect");
        close(sockfd);
        freeaddrinfo(res);
        return 0;
    }

    char request[256];
    snprintf(request, sizeof(request),
             "GET %s HTTP/1.1\r\n"
             "Host: %s\r\n"
             "Connection: close\r\n\r\n",
             path, host);

    send(sockfd, request, strlen(request), 0);

    memset(buf, 0, sizeof(buf));
    bytes = recv(sockfd, buf, sizeof(buf) - 1, 0);

    close(sockfd);
    freeaddrinfo(res);

    if (bytes <= 0)
    {
        perror("recv");
        return 0;
    }

    char *json = strstr(buf, "\r\n\r\n");
    json = json ? json + 4 : buf;
    return cb(json, bytes - (json - buf), user_data);
}

// ===================== 时间转换函数 =====================
static time_t convert_utc(const char *utc_time)
{
    struct tm t = {0};
    int year, mon, day, hour, min, sec;

    // 解析 ISO8601: "2025-09-03T22:41:12+00:00"
    if (sscanf(utc_time, "%d-%d-%dT%d:%d:%d",
               &year, &mon, &day, &hour, &min, &sec) != 6)
    {
        printf("Parse time failed: %s\n", utc_time);
        return 0;
    }

    if (mon <= 2)
    {
        year--;
        mon += 12;
    }

    int days_since_epoch = (365 * year) + (year / 4) - (year / 100) + (year / 400);
    days_since_epoch += (153 * mon - 457) / 5 + day - 306;

    return ((days_since_epoch - 719163) * 86400) + (hour * 3600) + (min * 60) + sec;

    // t.tm_year = year - 1900;
    // t.tm_mon = mon - 1;
    // t.tm_mday = day;
    // t.tm_hour = hour;
    // t.tm_min = min;
    // t.tm_sec = sec;
    // return timegm(&t); // 转成 UTC time_t
}

#ifdef ENABLE_TEST
static void convert_utc_to_local(time_t *time)
{
    struct tm t = {0};

    localtime_r(time, &t); // 加上本地时区偏移

    char buf[64];
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &t);
    printf("  -> Local time: %s\n", buf);
}
#endif

// ===================== API 2: 获取日出日落 =====================
static uint8_t get_sunrise_sunset(char *buf, size_t buf_size, void *user_data)
{
    char *sunrise = strstr(buf, "\"sunrise\"");
    char *sunset = strstr(buf, "\"sunset\"");
    if (!sunrise || !sunset)
    {
        printf("Parse sunrise/sunset failed\n");
        return 0;
    }
    sunrise_sunset_t *time = (sunrise_sunset_t *)user_data;
    char tmp[32];
    sscanf(sunrise, "\"sunrise\":\"%31[^\"]", tmp);
    time->sunrise = convert_utc(tmp);
#ifdef ENABLE_TEST
    printf("Sunrise (UTC): %s\n", tmp);
#endif
    sscanf(sunset, "\"sunset\":\"%31[^\"]", tmp);
    time->sunset = convert_utc(tmp);
#ifdef ENABLE_TEST
    printf("Sunset  (UTC): %s\n", tmp);
#endif
    return 1;
}

static uint8_t get_lat_lng(char *buf, size_t buf_size, void *user_data)
{
    char *plat = strstr(buf, "\"lat\"");
    char *plng = strstr(buf, "\"lon\"");
    char *ptz = strstr(buf, "\"timezone\"");
    if (!plat || !plng || !ptz)
    {
        printf("Parse lat/lon failed\n");
        return 0;
    }
    char *ptze = strchr(ptz + 12, '"');
    if (ptze)
        ptze[0] = '\0';
    coord_t *coord = (coord_t *)user_data;
    sscanf(plat, "\"lat\":%lf", &coord->lat);
    sscanf(plng, "\"lon\":%lf", &coord->lng);
    strncpy(coord->timezone, ptz + 12, sizeof(coord->timezone));
    return 1;
}

#ifndef ENABLE_TEST
uint8_t timer_update_tz_sunset_sunrise(timer_time_t *sunrise, timer_time_t *sunset)
{
    coord_t coord = {0};
    sunrise_sunset_t time = {0};
    uint8_t result = http_get("ip-api.com", "80", "/json", get_lat_lng, &coord);

    if (result)
    {
        char path[128];
        // char *tz = getenv("TZ");
        // if (!tz || strncmp(tz, coord.timezone, strlen(coord.timezone)) != 0)
        // {
        //     printf("update timezone %s -> %s\r\n", tz ? tz : "(null)", coord.timezone);
        //     setenv("TZ", coord.timezone, 1);
        //     tzset();
        // }

        snprintf(path, sizeof(path), "/json?lat=%.4f&lng=%.4f&formatted=0", coord.lat, coord.lng);
        result = http_get("api.sunrise-sunset.org", "80", path, get_sunrise_sunset, &time);
        if (result)
        {
            struct tm t = {0};
            localtime_r(&time.sunrise, &t);
            if (sunrise->hour != t.tm_hour || sunrise->minute != t.tm_min)
            {
                printf("update sunrise time %d:%d -> %d:%d\r\n", sunrise->hour, sunrise->minute, t.tm_hour, t.tm_min);
                sunrise->hour = t.tm_hour;
                sunrise->minute = t.tm_min;
            }
            localtime_r(&time.sunset, &t);
            if (sunset->hour != t.tm_hour || sunset->minute != t.tm_min)
            {
                printf("update sunset time %d:%d -> %d:%d\r\n", sunset->hour, sunset->minute, t.tm_hour, t.tm_min);
                sunset->hour = t.tm_hour;
                sunset->minute = t.tm_min;
            }
        }
    }
    return result;
}
#endif

// ===================== 测试入口 =====================
#ifdef ENABLE_TEST
int main()
{
    // ===================== API 1: 获取经纬度 =====================
    coord_t coord = {0};
    sunrise_sunset_t time = {0};
    uint8_t result = http_get("ip-api.com", "80", "/json", get_lat_lng, &coord);

    if (result)
    {
        char path[128];
        char *tz = getenv("TZ");
        if (!tz || strncmp(tz, coord.timezone, strlen(coord.timezone)) != 0)
        {
            printf("update timezone %s -> %s\r\n", tz, coord.timezone);
            setenv("TZ", coord.timezone, 1);
            tzset();
        }
        printf("Your location: lat=%.4f, lng=%.4f timezone:%s\n", coord.lat, coord.lng, coord.timezone);

        snprintf(path, sizeof(path), "/json?lat=%.4f&lng=%.4f&formatted=0", coord.lat, coord.lng);
        result = http_get("api.sunrise-sunset.org", "80", path, get_sunrise_sunset, &time);
        if (result)
        {
            convert_utc_to_local(&time.sunrise);
            convert_utc_to_local(&time.sunset);
        }
    }
    else
        printf("Failed to get location\n");

    return 0;
}

#endif